﻿// -----------------------------------------------------------------------
// <copyright file="MainController.cs" company="Abyssalsoft">
// TODO: Update copyright text.
// </copyright>
// -----------------------------------------------------------------------

namespace Metal.Player.Main
{
    using System;
    using System.Collections.Generic;
    using System.Reflection;
    using System.Text;
    using Core.Player;
    using Metal.Data;

    /// <summary>
    /// Main mask controller (audio and video - uses the same controller, the difference is in the view)
    /// </summary>
    public class MainController
    {
        #region Members

        /// <summary>Stores our view to communicate with the audio mask</summary>
        private static IMainView view;

        /// <summary>This timer is used to update some variables</summary>
        private System.Timers.Timer updateTimer;

        /// <summary>Dummy stuff</summary>
        private object objSender;

        /// <summary>Stores a value indicating the video is in full-screen</summary>
        private bool fullScreen;

        /// <summary>Stores last position of the form to be restored when exit from full-screen</summary>
        private System.Drawing.Rectangle rect;

        #endregion

        #region Constructor

        /// <summary>
        /// Initializes a new instance of the MainController class.
        /// </summary>
        /// <param name="iView">Interface to communicate with the mask</param>
        public MainController(IMainView iView)
        {
            try
            {
                view = iView;

                this.SubscribeToViewEvents();

                // Timer updater
                this.updateTimer = new System.Timers.Timer();
                this.updateTimer.Elapsed += new System.Timers.ElapsedEventHandler(this.TimerTick);
                this.updateTimer.Interval = 500;

                // Add KeyStroke listener (for Keyboard shortcuts)
                KeyboardListener keyStrokeMessageFilter = new KeyboardListener();
                System.Windows.Forms.Application.AddMessageFilter(keyStrokeMessageFilter);
            }
            catch (Exception ex)
            {
                Metal.User.UserMessage.ShowError(ex);
            }
        }

        #endregion

        #region Properties

        /// <summary>
        /// Gets or sets the view
        /// </summary>
        internal IMainView CurrentView
        {
            get
            {
                return view;
            }

            set
            {
                view = value;
            }
        }

        #endregion

        #region Methods

        /// <summary>
        /// Sets the current view (audio / video form)
        /// </summary>
        /// <param name="iView">The view which we must control</param>
        public void SetCurrentView(IMainView iView)
        {
            this.CurrentView = iView;
        }

        /// <summary>
        /// Subscribe to events defined in the view
        /// </summary>
        private void SubscribeToViewEvents()
        {
            // Mask events
            this.CurrentView.MaskLoad += new EventHandler(this.OnMaskLoad);
            this.CurrentView.MaskClose += new EventHandler(this.OnMaskClose);
            this.CurrentView.ControlAdded += new System.Windows.Forms.ControlEventHandler(this.OnControlAdded);
            this.CurrentView.MaskDoubleClick += new EventHandler(this.OnMaskDoubleClick);

            // Player events
            Events.Instance.Play += new EventHandler(this.OnPlay);
            Events.Instance.Stop += new EventHandler(this.OnStop);
        }

        /// <summary>
        /// Change volume
        /// </summary>
        private void Volume()
        {
            try
            {
                Playback.Instance.SetVolume((this.objSender as Gui.Controls.MetalSlider).Value);
            }
            catch (Exception ex)
            {
                Metal.User.UserMessage.ShowError(ex);
            }
        }

        /// <summary>
        /// Move current file position
        /// </summary>
        private void TrackBar()
        {
            try
            {
                Playback.Instance.Seek((this.objSender as Gui.Controls.MetalSlider).Value);
            }
            catch (Exception ex)
            {
                Metal.User.UserMessage.ShowError(ex);
            }
        }

        /// <summary>
        /// This timer updates some variables
        /// </summary>
        /// <param name="sender">Object sender</param>
        /// <param name="e">Event args</param>
        private void TimerTick(object sender, EventArgs e)
        {
            try
            {
                // Move scrollbar position
                if (MediaInfo.CurrentFile == Helper.FileTypeEnum.InternetAudioStream)
                {
                    this.CurrentView.TrackBarValue = 0;
                }
                else
                {
                    this.CurrentView.TrackBarValue = Convert.ToInt32(Status.CurrentPositionInSeconds);
                }
            }
            catch
            {
            }
        }

        #endregion

        #region Mask events

        /// <summary>
        /// This method is called when the mask is loaded.
        /// </summary>
        /// <param name="sender">Object sender</param>
        /// <param name="e">Event arguments</param>
        private void OnMaskLoad(object sender, EventArgs e)
        {
            try
            {
                DataStorage.SetProperty("FileName", "Metal Player");
                DataStorage.SetProperty("CurrentTime", "00:00");
                DataStorage.SetProperty("TotalTime", "00:00");
                DataStorage.SetProperty("Kbps", "0 Kbps");
                DataStorage.SetProperty("Frequency", "0 Khz");
                this.CurrentView.TrackBarValue = 0;
                this.CurrentView.Volume = Metal.Config.Settings.Instance.GetValue("LastSettings.Volume", 50);
                Status.Volume = Metal.Config.Settings.Instance.GetValue("LastSettings.Volume", 50);
                Settings.Instance.GraphicEqualizerStyle = Metal.Config.Settings.Instance.GetValue("LastSettings.VisualisationStyle", 4);
            }
            catch (Exception ex)
            {
                Metal.User.UserMessage.ShowError(ex);
            }
        }

        /// <summary>
        /// This method is called when the mask is closed.
        /// </summary>
        /// <param name="sender">Object sender</param>
        /// <param name="e">Event arguments</param>
        private void OnMaskClose(object sender, EventArgs e)
        {
            try
            {
                if (Status.PlaybackStatus != Status.StatusEnum.Stopped)
                {
                    Playback.Instance.Stop();
                }

                Metal.Config.Settings.Instance.SetValue("LastSettings.Volume", Core.Player.Status.Volume);
                Metal.Config.Settings.Instance.SetValue("LastSettings.VisualisationStyle", Core.Player.Settings.Instance.GraphicEqualizerStyle);
            }
            catch (Exception ex)
            {
                Metal.User.UserMessage.ShowError(ex);
            }
        }
 
        /// <summary>
        /// This event occurs on double click.
        /// </summary>
        /// <param name="sender">Object sender</param>
        /// <param name="e">Event arguments</param>
        private void OnMaskDoubleClick(object sender, EventArgs e)
        {
            try
            {
                if (this.fullScreen == false)
                {
                    // Save form position
                    this.rect.X = this.CurrentView.IForm.Left;
                    this.rect.Y = this.CurrentView.IForm.Top;
                    this.rect.Width = this.CurrentView.IForm.Width;
                    this.rect.Height = this.CurrentView.IForm.Height;

                    this.fullScreen = true;
                    this.CurrentView.HideControlsFullScreen = true;

                    System.Drawing.Rectangle monitorSize = System.Windows.Forms.Screen.FromControl(this.CurrentView.IForm).WorkingArea;

                    // If is on the first screen
                    if (monitorSize.X == 0)
                    {
                        this.CurrentView.IForm.Top = -2;
                        this.CurrentView.IForm.Left = -2;
                        this.CurrentView.IForm.Width = System.Windows.Forms.Screen.PrimaryScreen.Bounds.Width + 4;
                        this.CurrentView.IForm.Height = System.Windows.Forms.Screen.PrimaryScreen.Bounds.Height + 4;
                    }
                    else
                    {
                        this.CurrentView.IForm.Top = monitorSize.Y - 2;
                        this.CurrentView.IForm.Left = monitorSize.X - 2;
                        this.CurrentView.IForm.Width = monitorSize.Width + 4;
                        this.CurrentView.IForm.Height = monitorSize.Height + 4;
                    }

                    this.CurrentView.IForm.BringToFront();
                }
                else
                {
                    this.fullScreen = false;
                    this.CurrentView.HideControlsFullScreen = false;

                    this.CurrentView.IForm.Top = this.rect.Y;
                    this.CurrentView.IForm.Left = this.rect.X;
                    this.CurrentView.IForm.Width = this.rect.Width;
                    this.CurrentView.IForm.Height = this.rect.Height;
                }
            }
            catch (Exception ex)
            {
                Metal.User.UserMessage.ShowError(ex);
            }
        }

        /// <summary>
        /// This method is called when a control is added on the mask
        /// </summary>
        /// <param name="sender">Object sender</param>
        /// <param name="e">Event arguments</param>
        private void OnControlAdded(object sender, System.Windows.Forms.ControlEventArgs e)
        {
            try
            {
                if (e.Control.GetType() == typeof(Gui.Controls.MetalButton))
                {
                    e.Control.Click += new EventHandler(this.OnButtonClick);
                }
                else if (e.Control.GetType() == typeof(Gui.Controls.MetalSlider))
                {
                    (e.Control as Gui.Controls.MetalSlider).Scroll += new System.Windows.Forms.ScrollEventHandler(this.OnSliderDrag);
                }
                else if (e.Control.GetType() == typeof(Gui.Controls.MetalPanel))
                {
                    e.Control.ControlAdded += new System.Windows.Forms.ControlEventHandler(this.OnControlAdded);
                }
            }
            catch (Exception ex)
            {
                Metal.User.UserMessage.ShowError(ex);
            }
        }

        #endregion

        #region Controls events

        /// <summary>
        /// This event occurs when the user clicks on a button (doesn't matter what button)
        /// </summary>
        /// <param name="sender">Object sender</param>
        /// <param name="e">Event args</param>
        private void OnButtonClick(object sender, EventArgs e)
        {
            try
            {
                Type thisType = typeof(MainLogic);
                MethodInfo theMethod = thisType.GetMethod(((Gui.Controls.MetalButton)sender).Name, BindingFlags.Public | BindingFlags.Instance);
                if (theMethod != null)
                {
                    theMethod.Invoke(MainLogic.Instance, null);
                }
            }
            catch (Exception ex)
            {
                Metal.User.UserMessage.ShowError(ex);
            }
        }

        /// <summary>
        /// This event occurs when the slider is dragged
        /// </summary>
        /// <param name="sender">Object sender</param>
        /// <param name="e">Event args</param>
        private void OnSliderDrag(object sender, System.Windows.Forms.ScrollEventArgs e)
        {
            try
            {
                this.objSender = sender;
                Type thisType = typeof(MainController);
                MethodInfo theMethod = thisType.GetMethod(((Gui.Controls.MetalSlider)sender).Name, BindingFlags.NonPublic | BindingFlags.Instance);
                if (theMethod != null)
                {
                    theMethod.Invoke(this, null);
                }
            }
            catch (Exception ex)
            {
                Metal.User.UserMessage.ShowError(ex);
            }
        }

        #endregion

        #region PlayerEvents

        /// <summary>
        /// This event occurs when a new file is played
        /// </summary>
        /// <param name="sender">Object sender</param>
        /// <param name="e">Event args</param>
        private void OnPlay(object sender, EventArgs e)
        {
            try
            {
                // Update some stuff
                this.CurrentView.TrackBarMaximumValue = Convert.ToInt32(Status.TotalTimeInSeconds);
                this.updateTimer.Start();
            }
            catch (Exception ex)
            {
                Metal.User.UserMessage.ShowError(ex);
            }
        }

        /// <summary>
        /// This event occurs when the current playback is stopped
        /// </summary>
        /// <param name="sender">Object sender</param>
        /// <param name="e">Event args e</param>
        private void OnStop(object sender, EventArgs e)
        {
            try
            {
                this.updateTimer.Stop();
                DataStorage.SetProperty("FileName", "Metal Player");
                DataStorage.SetProperty("CurrentTime", "00:00");
                DataStorage.SetProperty("TotalTime", "00:00");
                DataStorage.SetProperty("Kbps", "0 Kbps");
                this.CurrentView.TrackBarValue = 0;
            }
            catch (Exception ex)
            {
                Metal.User.UserMessage.ShowError(ex);
            }
        }

        #endregion
    }
}
